#ifndef __WXSIZER_H__
#define __WXSIZER_H__

#include "wx/defs.h"

#include "wx/window.h"

class wxButton;
class wxBoxSizer;
class wxSizerItem;
class wxSizer;
class wxFlexGridSizer;
class wxGridBagSizer;

#ifndef wxUSE_BORDER_BY_DEFAULT
#ifdef __SMARTPHONE__

#define wxUSE_BORDER_BY_DEFAULT 0
#else
#define wxUSE_BORDER_BY_DEFAULT 1
#endif
#endif

class wxSizerFlags {
  public:


    wxSizerFlags( int proportion = 0 ) : m_proportion( proportion ) {
      m_flags = 0;
      m_borderInPixels = 0;
    }
    wxSizerFlags& Proportion( int proportion ) {
      m_proportion = proportion;
      return *this;
    }

    wxSizerFlags& Align( int alignment ) {
      m_flags &= ~wxALIGN_MASK;
      m_flags |= alignment;
      return *this;
    }

    wxSizerFlags& Expand() {
      m_flags |= wxEXPAND;
      return *this;
    }

    wxSizerFlags& Centre() { return Align( wxCENTRE ); }
    wxSizerFlags& Center() { return Centre(); }
    wxSizerFlags& Left() { return Align( wxALIGN_LEFT ); }
    wxSizerFlags& Right() { return Align( wxALIGN_RIGHT ); }
    wxSizerFlags& Top() { return Align( wxALIGN_TOP ); }
    wxSizerFlags& Bottom() { return Align( wxALIGN_BOTTOM ); }
    static int GetDefaultBorder() {
      return 5;
    }

    wxSizerFlags& Border( int direction, int borderInPixels ) {
      m_flags &= ~wxALL;
      m_flags |= direction;
      m_borderInPixels = borderInPixels;
      return *this;
    }

    wxSizerFlags& Border( int direction = wxALL ) {
      return Border( direction, GetDefaultBorder() );
    }

    wxSizerFlags& DoubleBorder( int direction = wxALL ) {
      return Border( direction, 2 * GetDefaultBorder() );
    }

    wxSizerFlags& TripleBorder( int direction = wxALL ) {
      return Border( direction, 3 * GetDefaultBorder() );
    }

    wxSizerFlags& HorzBorder() {
      return Border( wxLEFT | wxRIGHT, GetDefaultBorder() );
    }

    wxSizerFlags& DoubleHorzBorder() {
      return Border( wxLEFT | wxRIGHT, 2 * GetDefaultBorder() );
    }
    wxSizerFlags& Shaped() {
      m_flags |= wxSHAPED;
      return *this;
    }

    wxSizerFlags& FixedMinSize() {
      m_flags |= wxFIXED_MINSIZE;
      return *this;
    }
    wxSizerFlags& ReserveSpaceEvenIfHidden();


    int GetProportion() const { return m_proportion; }
    int GetFlags() const { return m_flags; }
    int GetBorderInPixels() const { return m_borderInPixels; }

  private:
    int m_proportion;
    int m_flags;
    int m_borderInPixels;
};

class wxSizerSpacer {
  public:
    wxSizerSpacer( const wxSize& size ) : m_size( size ), m_isShown( true ) { }
    void SetSize( const wxSize& size ) { m_size = size; }
    const wxSize& GetSize() const { return m_size; }
    void Show( bool show ) { m_isShown = show; }
    bool IsShown() const { return m_isShown; }
  private:
    wxSize m_size;
    bool m_isShown;
};

class wxSizerItem : public wxObject {
  public:
    wxSizerItem( wxWindow *window,
                 int proportion,
                 int flag,
                 int border,
                 wxObject* userData );


    wxSizerItem( wxWindow *window, const wxSizerFlags& flags ) {
      Init( flags );
      SetWindow( window );
    }


    wxSizerItem( wxSizer *sizer,
                 int proportion,
                 int flag,
                 int border,
                 wxObject* userData );


    wxSizerItem( wxSizer *sizer, const wxSizerFlags& flags ) {
      Init( flags );
      SetSizer( sizer );
    }


    wxSizerItem( int width,
                 int height,
                 int proportion,
                 int flag,
                 int border,
                 wxObject* userData );


    wxSizerItem( int width, int height, const wxSizerFlags& flags ) {
      Init( flags );
      SetSpacer( width, height );
    }

    wxSizerItem();
    virtual ~wxSizerItem();

    virtual void DeleteWindows();


    void DetachSizer() { m_sizer = NULL; }

    virtual wxSize GetSize() const;
    virtual wxSize CalcMin();
    virtual void SetDimension( const wxPoint& pos, const wxSize& size );

    wxSize GetMinSize() const
    { return m_minSize; }
    wxSize GetMinSizeWithBorder() const;

    void SetMinSize( const wxSize& size ) {
      if( IsWindow() ) {
        m_window->SetMinSize( size );
      }
      m_minSize = size;
    }
    void SetMinSize( int x, int y ) { SetMinSize( wxSize( x, y ) ); }
    void SetInitSize( int x, int y ) { SetMinSize( wxSize( x, y ) ); }



    void SetRatio( int width, int height ) { m_ratio = ( width && height ) ? ( ( float ) width / ( float ) height ) : 1; }
    void SetRatio( const wxSize& size ) { SetRatio( size.x, size.y ); }
    void SetRatio( float ratio ) { m_ratio = ratio; }
    float GetRatio() const
    { return m_ratio; }

    virtual wxRect GetRect() { return m_rect; }

    bool IsWindow() const { return m_kind == Item_Window; }
    bool IsSizer() const { return m_kind == Item_Sizer; }
    bool IsSpacer() const { return m_kind == Item_Spacer; }
    wxDEPRECATED( void SetOption( int option ) );
    wxDEPRECATED( int GetOption() const );
    void SetProportion( int proportion ) { m_proportion = proportion; }
    int GetProportion() const
    { return m_proportion; }
    void SetFlag( int flag ) { m_flag = flag; }
    int GetFlag() const
    { return m_flag; }
    void SetBorder( int border ) { m_border = border; }
    int GetBorder() const
    { return m_border; }

    wxWindow *GetWindow() const
    { return m_kind == Item_Window ? m_window : NULL; }
    wxSizer *GetSizer() const
    { return m_kind == Item_Sizer ? m_sizer : NULL; }
    wxSize GetSpacer() const;
    bool IsShown() const;
    void Show( bool show );

    void SetUserData( wxObject* userData ) { delete m_userData; m_userData = userData; }
    wxObject* GetUserData() const
    { return m_userData; }
    wxPoint GetPosition() const
    { return m_pos; }



    void SetWindow( wxWindow *window );
    void SetSizer( wxSizer *sizer );
    void SetSpacer( const wxSize& size );
    void SetSpacer( int width, int height ) { SetSpacer( wxSize( width, height ) ); }

  protected:

    void Init() { m_userData = NULL; }


    void Init( const wxSizerFlags& flags );



    enum {
      Item_None,
      Item_Window,
      Item_Sizer,
      Item_Spacer,
      Item_Max
    } m_kind;
    union {
      wxWindow      *m_window;
      wxSizer       *m_sizer;
      wxSizerSpacer *m_spacer;
    };

    wxPoint      m_pos;
    wxSize       m_minSize;
    int          m_proportion;
    int          m_border;
    int          m_flag;


    wxRect       m_rect;




    float        m_ratio;

    wxObject    *m_userData;

  private:

    bool ShouldAccountFor() const;

    DECLARE_CLASS( wxSizerItem )
    DECLARE_NO_COPY_CLASS( wxSizerItem )

    friend class wxBoxSizer;
    friend class wxFlexGridSizer;
    friend class wxGridBagSizer;
};

WX_DECLARE_EXPORTED_LIST( wxSizerItem, wxSizerItemList );






class wxSizer: public wxObject, public wxClientDataContainer {
  public:
    wxSizer() { m_containingWindow = NULL; }
    virtual ~wxSizer();



    wxSizerItem* Add( wxWindow *window,
                      int proportion = 0,
                      int flag = 0,
                      int border = 0,
                      wxObject* userData = NULL );
    wxSizerItem* Add( wxSizer *sizer,
                      int proportion = 0,
                      int flag = 0,
                      int border = 0,
                      wxObject* userData = NULL );
    wxSizerItem* Add( int width,
                      int height,
                      int proportion = 0,
                      int flag = 0,
                      int border = 0,
                      wxObject* userData = NULL );
    wxSizerItem* Add( wxWindow *window, const wxSizerFlags& flags );
    wxSizerItem* Add( wxSizer *sizer, const wxSizerFlags& flags );
    wxSizerItem* Add( wxSizerItem *item );

    wxSizerItem* AddSpacer( int size );
    wxSizerItem* AddStretchSpacer( int prop = 1 );

    wxSizerItem* Insert( size_t index,
                         wxWindow *window,
                         int proportion = 0,
                         int flag = 0,
                         int border = 0,
                         wxObject* userData = NULL );
    wxSizerItem* Insert( size_t index,
                         wxSizer *sizer,
                         int proportion = 0,
                         int flag = 0,
                         int border = 0,
                         wxObject* userData = NULL );
    wxSizerItem* Insert( size_t index,
                         int width,
                         int height,
                         int proportion = 0,
                         int flag = 0,
                         int border = 0,
                         wxObject* userData = NULL );
    wxSizerItem* Insert( size_t index,
                         wxWindow *window,
                         const wxSizerFlags& flags );
    wxSizerItem* Insert( size_t index,
                         wxSizer *sizer,
                         const wxSizerFlags& flags );
    virtual wxSizerItem* Insert( size_t index, wxSizerItem *item );

    wxSizerItem* InsertSpacer( size_t index, int size );
    wxSizerItem* InsertStretchSpacer( size_t index, int prop = 1 );

    wxSizerItem* Prepend( wxWindow *window,
                          int proportion = 0,
                          int flag = 0,
                          int border = 0,
                          wxObject* userData = NULL );
    wxSizerItem* Prepend( wxSizer *sizer,
                          int proportion = 0,
                          int flag = 0,
                          int border = 0,
                          wxObject* userData = NULL );
    wxSizerItem* Prepend( int width,
                          int height,
                          int proportion = 0,
                          int flag = 0,
                          int border = 0,
                          wxObject* userData = NULL );
    wxSizerItem* Prepend( wxWindow *window, const wxSizerFlags& flags );
    wxSizerItem* Prepend( wxSizer *sizer, const wxSizerFlags& flags );
    wxSizerItem* Prepend( wxSizerItem *item );

    wxSizerItem* PrependSpacer( int size );
    wxSizerItem* PrependStretchSpacer( int prop = 1 );



    void SetContainingWindow( wxWindow *window );
    wxWindow *GetContainingWindow() const { return m_containingWindow; }



    wxDEPRECATED( virtual bool Remove( wxWindow *window ) );
    virtual bool Remove( wxSizer *sizer );
    virtual bool Remove( int index );

    virtual bool Detach( wxWindow *window );
    virtual bool Detach( wxSizer *sizer );
    virtual bool Detach( int index );

    virtual bool Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive = false );
    virtual bool Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive = false );
    virtual bool Replace( size_t index, wxSizerItem *newitem );

    virtual void Clear( bool delete_windows = false );
    virtual void DeleteWindows();

    void SetMinSize( int width, int height ) { DoSetMinSize( width, height ); }
    void SetMinSize( const wxSize& size ) { DoSetMinSize( size.x, size.y ); }


    bool SetItemMinSize( wxWindow *window, int width, int height ) { return DoSetItemMinSize( window, width, height ); }
    bool SetItemMinSize( wxWindow *window, const wxSize& size ) { return DoSetItemMinSize( window, size.x, size.y ); }


    bool SetItemMinSize( wxSizer *sizer, int width, int height ) { return DoSetItemMinSize( sizer, width, height ); }
    bool SetItemMinSize( wxSizer *sizer, const wxSize& size ) { return DoSetItemMinSize( sizer, size.x, size.y ); }

    bool SetItemMinSize( size_t index, int width, int height ) { return DoSetItemMinSize( index, width, height ); }
    bool SetItemMinSize( size_t index, const wxSize& size ) { return DoSetItemMinSize( index, size.x, size.y ); }

    wxSize GetSize() const
    { return m_size; }
    wxPoint GetPosition() const
    { return m_position; }


    wxSize GetMinSize();

    virtual void RecalcSizes() = 0;
    virtual wxSize CalcMin() = 0;

    virtual void Layout();
    wxSize ComputeFittingClientSize( wxWindow *window );
    wxSize ComputeFittingWindowSize( wxWindow *window );

    wxSize Fit( wxWindow *window );
    void FitInside( wxWindow *window );
    void SetSizeHints( wxWindow *window );
    void SetVirtualSizeHints( wxWindow *window );

    wxSizerItemList& GetChildren() { return m_children; }

    void SetDimension( int x, int y, int width, int height );

    wxSizerItem* GetItem( wxWindow *window, bool recursive = false );
    wxSizerItem* GetItem( wxSizer *sizer, bool recursive = false );
    wxSizerItem* GetItem( size_t index );



    bool Show( wxWindow *window, bool show = true, bool recursive = false );
    bool Show( wxSizer *sizer, bool show = true, bool recursive = false );
    bool Show( size_t index, bool show = true );

    bool Hide( wxSizer *sizer, bool recursive = false ) { return Show( sizer, false, recursive ); }
    bool Hide( wxWindow *window, bool recursive = false ) { return Show( window, false, recursive ); }
    bool Hide( size_t index ) { return Show( index, false ); }

    bool IsShown( wxWindow *window ) const;
    bool IsShown( wxSizer *sizer ) const;
    bool IsShown( size_t index ) const;


    virtual void ShowItems( bool show );

    void Show( bool show ) { ShowItems( show ); }

  protected:
    wxSize              m_size;
    wxSize              m_minSize;
    wxPoint             m_position;
    wxSizerItemList     m_children;


    wxWindow *m_containingWindow;

    wxSize GetMaxWindowSize( wxWindow *window ) const;
    wxSize GetMinWindowSize( wxWindow *window );
    wxSize GetMaxClientSize( wxWindow *window ) const;
    wxSize GetMinClientSize( wxWindow *window );
    wxSize VirtualFitSize( wxWindow *window );

    virtual void DoSetMinSize( int width, int height );
    virtual bool DoSetItemMinSize( wxWindow *window, int width, int height );
    virtual bool DoSetItemMinSize( wxSizer *sizer, int width, int height );
    virtual bool DoSetItemMinSize( size_t index, int width, int height );

  private:
    DECLARE_CLASS( wxSizer )
};





class wxGridSizer: public wxSizer {
  public:
    wxGridSizer( int rows, int cols, int vgap, int hgap );
    wxGridSizer( int cols, int vgap = 0, int hgap = 0 );

    virtual void RecalcSizes();
    virtual wxSize CalcMin();

    void SetCols( int cols )    { m_cols = cols; }
    void SetRows( int rows )    { m_rows = rows; }
    void SetVGap( int gap )     { m_vgap = gap; }
    void SetHGap( int gap )     { m_hgap = gap; }
    int GetCols() const         { return m_cols; }
    int GetRows() const         { return m_rows; }
    int GetVGap() const         { return m_vgap; }
    int GetHGap() const         { return m_hgap; }

  protected:
    int    m_rows;
    int    m_cols;
    int    m_vgap;
    int    m_hgap;


    int CalcRowsCols( int& rows, int& cols ) const;

    void SetItemBounds( wxSizerItem *item, int x, int y, int w, int h );

  private:
    DECLARE_CLASS( wxGridSizer )
};







enum wxFlexSizerGrowMode {

  wxFLEX_GROWMODE_NONE,


  wxFLEX_GROWMODE_SPECIFIED,


  wxFLEX_GROWMODE_ALL
};

class wxFlexGridSizer: public wxGridSizer {
  public:

    wxFlexGridSizer( int rows, int cols, int vgap, int hgap );
    wxFlexGridSizer( int cols, int vgap = 0, int hgap = 0 );
    virtual ~wxFlexGridSizer();




    void AddGrowableRow( size_t idx, int proportion = 0 );
    void RemoveGrowableRow( size_t idx );
    void AddGrowableCol( size_t idx, int proportion = 0 );
    void RemoveGrowableCol( size_t idx );






    void SetFlexibleDirection( int direction ) { m_flexDirection = direction; }
    int GetFlexibleDirection() const { return m_flexDirection; }



    void SetNonFlexibleGrowMode( wxFlexSizerGrowMode mode ) { m_growMode = mode; }
    wxFlexSizerGrowMode GetNonFlexibleGrowMode() const { return m_growMode; }


    const wxArrayInt& GetRowHeights() const { return m_rowHeights; }
    const wxArrayInt& GetColWidths() const  { return m_colWidths; }


    virtual void RecalcSizes();
    virtual wxSize CalcMin();

  protected:
    void AdjustForFlexDirection();
    void AdjustForGrowables( const wxSize& sz, const wxSize& minsz,
                             int nrows, int ncols );


    wxArrayInt  m_rowHeights,
                m_colWidths;


    wxArrayInt  m_growableRows,
                m_growableCols;


    wxArrayInt  m_growableRowsProportions,
                m_growableColsProportions;



    int m_flexDirection;
    wxFlexSizerGrowMode m_growMode;


    wxSize m_calculatedMinSize;

  private:
    DECLARE_CLASS( wxFlexGridSizer )
    DECLARE_NO_COPY_CLASS( wxFlexGridSizer )
};





class wxBoxSizer: public wxSizer {
  public:
    wxBoxSizer( int orient );

    void RecalcSizes();
    wxSize CalcMin();

    int GetOrientation() const
    { return m_orient; }

    void SetOrientation( int orient ) { m_orient = orient; }

  protected:
    int m_orient;
    int m_stretchable;
    int m_minWidth;
    int m_minHeight;
    int m_fixedWidth;
    int m_fixedHeight;

  private:
    DECLARE_CLASS( wxBoxSizer )
};





#if wxUSE_STATBOX

class wxStaticBox;

class wxStaticBoxSizer: public wxBoxSizer {
  public:
    wxStaticBoxSizer( wxStaticBox *box, int orient );
    wxStaticBoxSizer( int orient, wxWindow *win, const wxString& label = wxEmptyString );
    virtual ~wxStaticBoxSizer();

    void RecalcSizes();
    wxSize CalcMin();

    wxStaticBox *GetStaticBox() const
    { return m_staticBox; }


    virtual void ShowItems( bool show );

    virtual bool Detach( wxWindow *window );
    virtual bool Detach( wxSizer *sizer ) { return wxBoxSizer::Detach( sizer ); }
    virtual bool Detach( int index ) { return wxBoxSizer::Detach( index ); }

  protected:
    wxStaticBox   *m_staticBox;

  private:
    DECLARE_CLASS( wxStaticBoxSizer )
    DECLARE_NO_COPY_CLASS( wxStaticBoxSizer )
};

#endif

#if wxUSE_BUTTON

class wxStdDialogButtonSizer: public wxBoxSizer {
  public:
    wxStdDialogButtonSizer();
    void AddButton( wxButton *button );
    void SetAffirmativeButton( wxButton *button );
    void SetNegativeButton( wxButton *button );
    void SetCancelButton( wxButton *button );
    void Realize();
    wxButton *GetAffirmativeButton() const { return m_buttonAffirmative; }
    wxButton *GetApplyButton() const { return m_buttonApply; }
    wxButton *GetNegativeButton() const { return m_buttonNegative; }
    wxButton *GetCancelButton() const { return m_buttonCancel; }
    wxButton *GetHelpButton() const { return m_buttonHelp; }

  protected:
    wxButton *m_buttonAffirmative;
    wxButton *m_buttonApply;
    wxButton *m_buttonNegative;
    wxButton *m_buttonCancel;
    wxButton *m_buttonHelp;

  private:
    DECLARE_CLASS( wxStdDialogButtonSizer )
    DECLARE_NO_COPY_CLASS( wxStdDialogButtonSizer )
};

#endif

inline wxSizerItem*
wxSizer::Add( wxSizerItem *item ) {
  return Insert( m_children.GetCount(), item );
}

inline wxSizerItem*
wxSizer::Add( wxWindow *window, int proportion, int flag, int border, wxObject* userData ) {
  return Add( new wxSizerItem( window, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::Add( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData ) {
  return Add( new wxSizerItem( sizer, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::Add( int width, int height, int proportion, int flag, int border, wxObject* userData ) {
  return Add( new wxSizerItem( width, height, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::Add( wxWindow *window, const wxSizerFlags& flags ) {
  return Add( new wxSizerItem( window, flags ) );
}

inline wxSizerItem*
wxSizer::Add( wxSizer *sizer, const wxSizerFlags& flags ) {
  return Add( new wxSizerItem( sizer, flags ) );
}

inline wxSizerItem*
wxSizer::AddSpacer( int size ) {
  return Add( size, size );
}

inline wxSizerItem*
wxSizer::AddStretchSpacer( int prop ) {
  return Add( 0, 0, prop );
}

inline wxSizerItem*
wxSizer::Prepend( wxSizerItem *item ) {
  return Insert( 0, item );
}

inline wxSizerItem*
wxSizer::Prepend( wxWindow *window, int proportion, int flag, int border, wxObject* userData ) {
  return Prepend( new wxSizerItem( window, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::Prepend( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData ) {
  return Prepend( new wxSizerItem( sizer, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::Prepend( int width, int height, int proportion, int flag, int border, wxObject* userData ) {
  return Prepend( new wxSizerItem( width, height, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::PrependSpacer( int size ) {
  return Prepend( size, size );
}

inline wxSizerItem*
wxSizer::PrependStretchSpacer( int prop ) {
  return Prepend( 0, 0, prop );
}

inline wxSizerItem*
wxSizer::Prepend( wxWindow *window, const wxSizerFlags& flags ) {
  return Prepend( new wxSizerItem( window, flags ) );
}

inline wxSizerItem*
wxSizer::Prepend( wxSizer *sizer, const wxSizerFlags& flags ) {
  return Prepend( new wxSizerItem( sizer, flags ) );
}

inline wxSizerItem*
wxSizer::Insert( size_t index,
                 wxWindow *window,
                 int proportion,
                 int flag,
                 int border,
                 wxObject* userData ) {
  return Insert( index, new wxSizerItem( window, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::Insert( size_t index,
                 wxSizer *sizer,
                 int proportion,
                 int flag,
                 int border,
                 wxObject* userData ) {
  return Insert( index, new wxSizerItem( sizer, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::Insert( size_t index,
                 int width,
                 int height,
                 int proportion,
                 int flag,
                 int border,
                 wxObject* userData ) {
  return Insert( index, new wxSizerItem( width, height, proportion, flag, border, userData ) );
}

inline wxSizerItem*
wxSizer::Insert( size_t index, wxWindow *window, const wxSizerFlags& flags ) {
  return Insert( index, new wxSizerItem( window, flags ) );
}

inline wxSizerItem*
wxSizer::Insert( size_t index, wxSizer *sizer, const wxSizerFlags& flags ) {
  return Insert( index, new wxSizerItem( sizer, flags ) );
}

inline wxSizerItem*
wxSizer::InsertSpacer( size_t index, int size ) {
  return Insert( index, size, size );
}

inline wxSizerItem*
wxSizer::InsertStretchSpacer( size_t index, int prop ) {
  return Insert( index, 0, 0, prop );
}


#endif
